#ifndef HCELL_CELL_INCLUDED
#define HCELL_CELL_INCLUDED 1

#include "./chemistry.hpp"
#include "yocto/math/ode/drvck.hpp"
#include "yocto/aqueous/lua.hpp"
#include "yocto/lua/lua-maths.hpp"

typedef ode::drvck<double>::type DiffSolver;
typedef DiffSolver::equation     DiffEquation;
typedef _lua::effector           Effector;
typedef _lua::effectors          Effectors;


class Cell : public Chemistry
{
public:
    explicit Cell( const string &cfgfile );
    virtual ~Cell() throw();
    
    const double surface; //!< microns^2
    const double volume;  //!< microns^3
    const double liters;  //!< volume in liters = 1e-15 * volume
    const double Cm;      //!< membranar capacity in microFarad.cm^2, centiFarad/m^2
    const double Capa;    //!< C, in Farad = Cm * S * 1e-14
    
    static const size_t NEXTRA    = 1;
    static const size_t Em_OFFSET = 1; 
    
    const size_t   M;         //!< lib size
    const size_t   nvar;      //!< M+NEXTRA
    const size_t   iEm;       //!< Em offset
    solution       sol;       //!< current solution
    double         Em;        //!< current potential, default is 0
    solution       acc;       //!< solution accumulator for computation
    
    //! append to leak the corresponding delta concentration
    void Leak( solution &leak, double zeta, const solution &Sin, const solution &Sout ) const;
    
    
    void Step( double t_ini, double t_end );
    
    //! compute Em assuming permeabilities are fine
    void ComputeSteadyEm();
    
    //! enforce Em assuming K+ permeability is biased
    void EnforceSteadyEm( double E );
    
    //! rescale effectors w.r.t to permeabilities, Em and pH
    void RescaleEffectors();
    
    //! rescale all time constants
    void RescaleAllRates( double coeff ) throw();
    
    void TryRescaleAllRates(); //!< find a rescale_rates in lua_State
    
    void ReloadInside();
    
    
    void load_state( const array<double> &data ) throw(); //# data.size() >= nvar
    void save_state( array<double> &data ) const throw(); //# data.size() >= nvar
    
private:
    YOCTO_DISABLE_COPY_AND_ASSIGN(Cell);
    Effectors             effectors; //!< all the effectors
    solution              tmp;        //!< temporary inside solution
    solution              perm_coeff; //!< coefficient for permeabilities
    DiffSolver            ode_solver;
    DiffEquation          ode_derivs;
    vector<double>        variables;  //!< variables
    void compute( array<double> &dYdt, double t, const array<double> &Y );
    double ComputeZeroLeak( double E );
    double EnforceZeroLeak( double Coeff );
    double GetP_CO2(double);
    
public:
    double                            dt_max;        //!< adaptive hint
    mutable numeric<double>::function P_CO2;         //!< from lua
};

#endif
